import {minStepKeyValue} from './WolfAiData'
import {WolfScore} from "./wolfScore";
import {SheepScore} from "./SheepScore";
export class WolfAi {
  stepKeyValue:Map<any,any>
  wolfScore:WolfScore
  sheepScore:SheepScore
  // Check possible moves for each sheep
  directions = [{
    dx: 1,
    dy: 0
  }, // Down
    {
      dx: -1,
      dy: 0
    }, // Up
    {
      dx: 0,
      dy: 1
    }, // Right
    {
      dx: 0,
      dy: -1
    } // Left
  ];
  private decimalToTernary(decimal) {
    if (decimal === 0) return "0";
    let result = "";
    while (decimal > 0) {
      result = (decimal % 3) + result;
      decimal = Math.floor(decimal / 3);
    }
    return result;
  }
  constructor() {
    this.stepKeyValue=new Map<any, any>()
    Object.keys(minStepKeyValue).forEach(key=>{
      let newKey=this.decimalToTernary(key)
      let value=minStepKeyValue[key]
      let newValue={}
      Object.keys(value).forEach(itemKey=>{
        let newItemKey=this.decimalToTernary(itemKey)
        newValue[newItemKey]=value[itemKey]
      })
      this.stepKeyValue[newKey]=newValue
    })
    this.wolfScore=new WolfScore()
    this.sheepScore=new SheepScore()
  }
  private convertKey(matrix) {
    let key = ''
    for (let arr of matrix) {
      for (let item of arr) {
        key += item
      }
    }
    return BigInt(key)
  }

  private deserialize(value) {
    let v = `${value}`
    let vv = v.padStart(25, '0')
    let matrix = []
    let i = 0;
    let item = []
    for (let c of vv) {
      item.push(c)
      i++;
      if (i == 5) {
        matrix.push([...item])
        i = 0;
        item = []
      }
    }
    return matrix
  }

  public itemsChar(matrix, c) {
    let items = []
    let dx = 0
    for (let arr of matrix) {
      let dy = 0
      for (let item of arr) {
        if (item == c) {
          items.push({
            x: dx,
            y: dy
          })
        }
        dy++
      }
      dx++
    }
    return items
  }
  //获取狼移动位置，如果有吃的优先吃
  private getWolfMoves(board, wolfItems,withScore=false) {
    const moves = [];
    const highMoves=[]
    wolfItems.forEach(wolfPos=>{
      this.directions.forEach(dir => {
        const nextPos = {
          x: wolfPos.x + dir.dx,
          y: wolfPos.y + dir.dy
        };
        const jumpPos = {
          x: wolfPos.x + 2 * dir.dx,
          y: wolfPos.y + 2 * dir.dy
        };

        // Check if can jump over a sheep
        if (
          nextPos.x >= 0 &&
          nextPos.y >= 0 &&
          nextPos.x < board.length &&
          nextPos.y < board[0].length &&
          board[nextPos.x][nextPos.y] == 0 &&
          jumpPos.x >= 0 &&
          jumpPos.y >= 0 &&
          jumpPos.x < board.length &&
          jumpPos.y < board[0].length &&
          board[jumpPos.x][jumpPos.y] == 1
        ) {
          let score=0
          if (withScore){
            score=this.getSheepScore(this.doWolfMove(board,wolfPos,jumpPos))
          }
          highMoves.push({from:wolfPos,to:jumpPos,score});
          highMoves.sort((a,b)=> a.score-b.score )
        }

        // Check if can move forward one step
        else if (
          nextPos.x >= 0 &&
          nextPos.y >= 0 &&
          nextPos.x < board.length &&
          nextPos.y < board[0].length &&
          board[nextPos.x][nextPos.y] == 0
        ) {
          let score=0
          if (withScore){
            score=this.getSheepScore(this.doWolfMove(board,wolfPos,nextPos))
          }
          moves.push({from:wolfPos,to:nextPos,score});
          moves.sort((a,b)=> a.score-b.score )
        }
      });
    })
    // console.log(highMoves)
    // console.log(moves)
    return {highMoves,moves};
  }

  private doWolfMove(matrix, wolfPos, wolfMove) {
    let newMatrix = this.deserialize(this.convertKey(matrix))
    newMatrix[wolfPos.x][wolfPos.y] = 0
    newMatrix[wolfMove.x][wolfMove.y] = 2
    return newMatrix
  }
  wolfStep(matrix) {
    //获取AI位置
    let keyOld=this.convertKey(matrix)
    let aiExist=this.stepKeyValue[keyOld]
    let newMatrix
    if(aiExist){
      console.log('ai found')
      let stepKeys=Object.keys(aiExist)
      let stepNum=stepKeys.length
      //如果只有一个方案则直接返回
      if(stepNum==1){
        newMatrix=this.deserialize(stepKeys[0])
      }else{
        let idx = Math.floor(Math.random() * stepNum)
        newMatrix=this.deserialize(stepKeys[idx])
      }
    }else{
      console.log('ai not find')
      let wolfItems = this.itemsChar(matrix, 2)
      let wolfPos
      let wolfMove
      let {highMoves,moves}=this.getWolfMoves(matrix,wolfItems,true)
      //优先走吃羊的子
      if(highMoves.length>0){
        let {from,to}=highMoves[0]
        //根据第几个，判断落点
        wolfPos=from
        wolfMove=to
      }else if(moves.length>0){
        let {from,to}=moves[0]
        //根据第几个，判断落点
        wolfPos=from
        wolfMove=to
      }else{
        // console.log('狼无位置可走')
        return null;
      }
      newMatrix = this.doWolfMove(matrix, wolfPos, wolfMove)
    }
    return newMatrix
  }
  //获取能移动的位置
  getSheepCanMovePos(board){
    let sheepItems = this.itemsChar(board, 1)
    const moves = [];

    sheepItems.forEach(sheepPos=>{
      this.directions.forEach(dir => {
        const nextPos = {
          x: sheepPos.x + dir.dx,
          y: sheepPos.y + dir.dy
        };
        if (
          nextPos.x >= 0 &&
          nextPos.y >= 0 &&
          nextPos.x < board.length &&
          nextPos.y < board[0].length &&
          board[nextPos.x][nextPos.y] == 0 // Check if the next position is empty
        ) {
          moves.push(sheepPos.x*5+sheepPos.y);
        }
      });
    })
    // console.log(moves)
    return moves;
  }
  getSheepCanMoveTo(board,sheepPos){
    let moves=[]
    this.directions.forEach(dir => {
      const nextPos = {
        x: sheepPos.x + dir.dx,
        y: sheepPos.y + dir.dy
      };
      if (
        nextPos.x >= 0 &&
        nextPos.y >= 0 &&
        nextPos.x < board.length &&
        nextPos.y < board[0].length &&
        board[nextPos.x][nextPos.y] == 0 // Check if the next position is empty
      ) {
        console.log(nextPos)
        moves.push(nextPos.x*5+nextPos.y);
      }
    });
    return moves
  }
  // private getWolfScore(board){
  //   //计算评分，如果狼有吃到的子，则x10，如果有移动的位置则+1
  //   let {highMoves,moves}=this.getWolfMoves(board,this.itemsChar(board, 2))
  //   return highMoves.length*10+moves.length
  // }
  private getWolfScore(board){
    let gameState=this.wolfScore.convertGameState(board)
    return this.wolfScore.evaluateWolvesScore(gameState)
  }
  private getSheepScore(board){
    // console.log(JSON.stringify(board))
    let score=this.sheepScore.evaluateSheepScore(board,10,1,50)
    // console.log(score)
    return score
  }
}
